/* ----------------------------------------------------------------------------
 * Copyright (c) Huawei Technologies Co., Ltd. 2013-2019. All rights reserved.
 * Description: ShellCmd Task
 * Author: liulei
 * Create: 2013-01-01
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 * of conditions and the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 * to endorse or promote products derived from this software without specific prior written
 * permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------------
 * Notice of Export Control Law
 * ===============================================
 * Huawei LiteOS may be subject to applicable export control laws and regulations, which might
 * include those applicable to Huawei LiteOS of U.S. and the country in which you are located.
 * Import, export and usage of Huawei LiteOS in any manner by you shall be in compliance with such
 * applicable export control laws and regulations.
 * --------------------------------------------------------------------------- */
#include "los_config.h"
#include "stdio.h"
#include "stdlib.h"
#include "los_exc.h"
#include "string.h"
#include "los_memstat_pri.h"
#include "los_sem_pri.h"
#include "los_task_pri.h"
#ifdef LOSCFG_SHELL
#include "shcmd.h"
#include "shell.h"
#endif
#ifdef LOSCFG_KERNEL_CPUP
#include "los_cpup_pri.h"
#endif
#ifdef LOSCFG_SHELL_EXCINFO
#include "los_excinfo_pri.h"
#endif


#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */

LITE_OS_SEC_TEXT_MINOR UINT8 *osShellCmdConvertTskStatus(UINT16 taskStatus)
{
    if (OS_TASK_STATUS_RUNNING & taskStatus) {
        return (UINT8 *)"Running";
    } else if (OS_TASK_STATUS_READY & taskStatus) {
        return (UINT8 *)"Ready";
    } else {
        if (OS_TASK_STATUS_DELAY & taskStatus) {
            return (UINT8 *)"Delay";
        } else if (OS_TASK_STATUS_PEND_TIME & taskStatus) {
            if (OS_TASK_STATUS_SUSPEND & taskStatus) {
                return (UINT8 *)"SuspendTime";
            } else if (OS_TASK_STATUS_PEND & taskStatus) {
                return (UINT8 *)"PendTime";
            } else if (OS_TASK_STATUS_PEND_QUEUE & taskStatus) {
                return (UINT8 *)"QueuePendTime";
            }
        } else if (OS_TASK_STATUS_PEND & taskStatus) {
            return (UINT8 *)"Pend";
        } else if (OS_TASK_STATUS_PEND_QUEUE & taskStatus) {
            return (UINT8 *)"QueuePend";
        } else if (OS_TASK_STATUS_SUSPEND & taskStatus) {
            return (UINT8 *)"Suspend";
        }
    }

    return (UINT8 *)"Invalid";
}

UINT32 osShellCmdTaskWaterLineGet(UINT32 taskID)
{
    AARCHPTR *stack = NULL;
    UINT32 peakUsed;

    if (*(AARCHPTR *)(((LosTaskCB *)g_taskCBArray) + taskID)->topOfStack == OS_TASK_MAGIC_WORD) {
        stack = (AARCHPTR *)((((LosTaskCB *)g_taskCBArray) + taskID)->topOfStack + sizeof(AARCHPTR));
        while ((stack < (AARCHPTR *)(((LosTaskCB *)g_taskCBArray) + taskID)->stackPointer) &&
               (*stack == OS_TASK_STACK_INIT)) {
            stack += 1;
        }
        peakUsed = ((((LosTaskCB *)g_taskCBArray) + taskID)->stackSize -
            ((AARCHPTR)stack - (((LosTaskCB *)g_taskCBArray) + taskID)->topOfStack));
    } else {
        PRINTK("CURRENT task %s stack overflow!\n", (((LosTaskCB *)g_taskCBArray) + taskID)->taskName);
        peakUsed = 0xFFFFFFFF;
    }
    return peakUsed;
}

LITE_OS_SEC_TEXT_MINOR UINT32 osShellCmdTskInfoGet(UINT32 taskID)
{
    LosTaskCB *taskCB = NULL;
    UINT32 loop;
    UINT16 semID;

    if (taskID == 0xffffffff) {
#ifdef LOSCFG_KERNEL_CPUP
        (VOID)memset_s((VOID *)g_taskCpupAll, sizeof(CPUP_INFO_S) * g_taskCpupMaxNum, 0,
                        sizeof(CPUP_INFO_S) * g_taskCpupMaxNum);
        (VOID)memset_s((VOID *)g_taskCpup10s, sizeof(CPUP_INFO_S) * g_taskCpupMaxNum, 0,
                        sizeof(CPUP_INFO_S) * g_taskCpupMaxNum);
        (VOID)memset_s((VOID *)g_taskCpup1s, sizeof(CPUP_INFO_S) * g_taskCpupMaxNum, 0,
                        sizeof(CPUP_INFO_S) * g_taskCpupMaxNum);

        LOS_TaskLock();
        (VOID)LOS_AllCpuUsage(g_taskCpupMaxNum, g_taskCpupAll, 0xffff, 1);
        (VOID)LOS_AllCpuUsage(g_taskCpupMaxNum, g_taskCpup10s, 0, 1);
        (VOID)LOS_AllCpuUsage(g_taskCpupMaxNum, g_taskCpup1s, 1, 1);
        LOS_TaskUnlock();
#endif

        PRINTK("\r\nName                   TaskEntryAddr       TID    Priority   Status       StackSize    WaterLine    StackPoint  TopOfStack   EventMask  SemID");
#ifdef LOSCFG_SHELL_EXCINFO
        WriteExcInfoToBuf("\r\nName                  TaskEntryAddr       TID    Priority   Status       "
                          "StackSize    WaterLine    StackPoint  TopOfStack   EventMask  SemID");
#endif
#ifdef LOSCFG_KERNEL_CPUP
        PRINTK("  CPUUSE  CPUUSE10s  CPUUSE1s  ");
#ifdef LOSCFG_SHELL_EXCINFO
        WriteExcInfoToBuf("  CPUUSE  CPUUSE10s  CPUUSE1s  ");
#endif
#endif /* LOSCFG_KERNEL_CPUP */
        PRINTK(" MEMUSE\n");
        PRINTK("----                   -------------       ---    --------   --------     ---------    ----------   ----------  ----------   ---------  -----");
#ifdef LOSCFG_SHELL_EXCINFO
        WriteExcInfoToBuf(" MEMUSE\n----                   -------------       ---    --------   --------     "
                          "---------    ----------   ----------  ----------   ---------  -----");
#endif
#ifdef LOSCFG_KERNEL_CPUP
        PRINTK("  ------- ---------  ---------");
#ifdef LOSCFG_SHELL_EXCINFO
        WriteExcInfoToBuf("  ------- ---------  ---------");
#endif
#endif /* LOSCFG_KERNEL_CPUP */
        PRINTK("  -------\n");
#ifdef LOSCFG_SHELL_EXCINFO
        WriteExcInfoToBuf("  -------\n");
#endif
        for (loop = 0; loop < g_taskMaxNum; loop++) {
            taskCB = (((LosTaskCB *)g_taskCBArray) + loop);
            if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) {
                continue;
            }

            if (taskCB->taskSem != NULL) {
                semID = ((LosSemCB *)taskCB->taskSem)->semID;
            } else {
                semID = 0xFFFF;
            }

            PRINTK("%-23s"
                   "%-20p"
                   "0x%-5x"
                   "%-11d"
                   "%-13s"
                   "0x%-11x"
                   "0x%-11x"
                   " %p "
                   " %p "
                   "0x%-9x"
                   "0x%-7hx",
                   taskCB->taskName,
                   taskCB->taskEntry,
                   taskCB->taskID,
                   taskCB->priority,
                   osShellCmdConvertTskStatus(taskCB->taskStatus),
                   taskCB->stackSize,
                   osShellCmdTaskWaterLineGet(taskCB->taskID),
                   taskCB->stackPointer,
                   taskCB->topOfStack,
                   taskCB->eventMask,
                   semID);
#ifdef LOSCFG_SHELL_EXCINFO
            WriteExcInfoToBuf("%-23s"
                              "%-20p"
                              "0x%-5x"
                              "%-11d"
                              "%-13s"
                              "0x%-11x"
                              "0x%-11x"
                              " %p "
                              " %p "
                              "0x%-9x"
                              "0x%-7hx",
                              taskCB->taskName,
                              taskCB->taskEntry,
                              taskCB->taskID,
                              taskCB->priority,
                              osShellCmdConvertTskStatus(taskCB->taskStatus),
                              taskCB->stackSize,
                              osShellCmdTaskWaterLineGet(taskCB->taskID),
                              taskCB->stackPointer,
                              taskCB->topOfStack,
                              taskCB->eventMask,
                              semID);
#endif
#ifdef LOSCFG_KERNEL_CPUP
            PRINTK("%2d.%-7d"
                   "%2d.%-9d"
                   "%2d.%-6d",
                   g_taskCpupAll[taskCB->taskID].uwUsage / LOS_CPUP_PRECISION_MULT,
                   g_taskCpupAll[taskCB->taskID].uwUsage % LOS_CPUP_PRECISION_MULT,
                   g_taskCpup10s[taskCB->taskID].uwUsage / LOS_CPUP_PRECISION_MULT,
                   g_taskCpup10s[taskCB->taskID].uwUsage % LOS_CPUP_PRECISION_MULT,
                   g_taskCpup1s[taskCB->taskID].uwUsage / LOS_CPUP_PRECISION_MULT,
                   g_taskCpup1s[taskCB->taskID].uwUsage % LOS_CPUP_PRECISION_MULT);
#ifdef LOSCFG_SHELL_EXCINFO
            WriteExcInfoToBuf("%2d.%-7d"
                              "%2d.%-9d"
                              "%2d.%-6d",
                              g_taskCpupAll[taskCB->taskID].uwUsage / LOS_CPUP_PRECISION_MULT,
                              g_taskCpupAll[taskCB->taskID].uwUsage % LOS_CPUP_PRECISION_MULT,
                              g_taskCpup10s[taskCB->taskID].uwUsage / LOS_CPUP_PRECISION_MULT,
                              g_taskCpup10s[taskCB->taskID].uwUsage % LOS_CPUP_PRECISION_MULT,
                              g_taskCpup1s[taskCB->taskID].uwUsage / LOS_CPUP_PRECISION_MULT,
                              g_taskCpup1s[taskCB->taskID].uwUsage % LOS_CPUP_PRECISION_MULT);
#endif
#endif /* LOSCFG_KERNEL_CPUP */
            PRINTK("%-11d\n", OsTaskMemUsage(taskCB->taskID));
#ifdef LOSCFG_SHELL_EXCINFO
            WriteExcInfoToBuf("%-11d\n", OsTaskMemUsage(taskCB->taskID));
#endif
        }
    } else {
        osTaskBackTrace(taskID);
    }

    return LOS_OK;
}

LITE_OS_SEC_TEXT_MINOR UINT32 osShellCmdDumpTask(INT32 argc, CHAR **argv)
{
    UINT32 taskID;
    CHAR *endPtr = NULL;

    if (argc < 2) {
        if (argc == 0) {
            taskID = 0xffffffff;
        } else {
            taskID = strtoul(argv[0], &endPtr, 0);
            if (*endPtr != 0 || (INT32)taskID < 0) {
                PRINTK("\ntask ID can't access %s.\n", argv[0]);
                return (UINT32)-1;
            }
        }

        (void)osShellCmdTskInfoGet(taskID);
    } else {
        PRINTK("\nUsage: task or task ID\n");
    }
    return 0;
}

#ifdef LOSCFG_SHELL
SHELLCMD_ENTRY(task_shellcmd, CMD_TYPE_EX, "task", 1, (CMD_CBK_FUNC)osShellCmdDumpTask); /*lint !e19*/
#endif

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
